/* 
 * File:   Client.cpp
 * Author: brady
 * 
 * Created on October 17, 2010, 9:16 PM
 */

#include <vector>

#include "Client.h"

#define buffer_size 10000

Client::Client(string sock_type, int ipv) {
    if (sock_type == "tcp") {
        sockType = SOCK_STREAM;
    } else {
        sockType = SOCK_DGRAM;
    }

    if (ipv == 4) {
        IPv = AF_INET;
    } else {
        IPv = AF_INET6;
    }
}

void Client::Connect(string host, int port) {

    memset(&hints, 0, sizeof hints);
    hints.ai_family = IPv;
    hints.ai_socktype = sockType;


    ostringstream s;
    s << port;
    int aierr;
    int conerr;
    aierr = getaddrinfo(host.c_str(), s.str().c_str(), &hints, &serverInfo);

    #ifdef DEBUG
    if (aierr != 0) {
        cout << "Host not found\n";
    }
    #endif

    for (p = serverInfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            continue; //bad socket, try next
        }
        conerr = connect(sockfd, p->ai_addr, p->ai_addrlen);
        if (conerr == -1) {
            close(sockfd);
            continue; //can't connect, try next
        }
        break;
    }
    if (conerr == 0) {
        char ip[INET6_ADDRSTRLEN];
        inet_ntop(serverInfo->ai_family, serverInfo->ai_addr, ip, sizeof ip);

        #ifdef DEBUG
        cout << "Connecting to: " << ip << "\n";
        #endif

    }

    #ifdef DEBUG
    else cout << "Failed to connect\n";
    #endif
    
    freeaddrinfo(serverInfo);
}

void Client::Disconnect() {
    close(sockfd);
}

int Client::Send(void* data, int length) {
    return send(sockfd, data, length, 0);
}

int Client::SendString(string msg)
{
    char* data = (char*)msg.c_str();
    data[msg.size()] = '\0';
    return send(sockfd, data, msg.length()+1, 0);
}

void Client::SendFile(string prefix, string fpath, string suffix)
{
    string fullstring;
    ifstream file(fpath.c_str(), fstream::in);
    stringstream prefss;
    prefss << prefix;
    stringstream suffss;
    suffss << suffix;
    if (file.is_open()) {
        vector<char> data;
        //allocate room for prefix and read prefix into data
        data.resize(prefix.size());
        prefss.read(&data[0], prefix.size());
        while (!file.eof()) {
            //allocate an additional buffer_size bytes
            data.resize(data.size()+buffer_size);
            //read up to buffer_size bytes into the data vector from the file
            file.read(&data.at(data.size()-buffer_size), buffer_size);
            //trim all unused bytes from the end of the file.
            //if buffer_size bytes were read, trims 0 bytes.
            data.resize(data.size() - (buffer_size - file.gcount()));
        }
        //allocate some room for suffix and read it into data
        data.reserve(data.size() + suffix.size() + 1);
        suffss.read(&data[data.size() - suffix.size()], suffix.size());

        Send(data.data(), data.size());
    } else {
      //file didn't open, do something.
    }
}

void Client::SendFile(string fpath)
{
    SendFile("", fpath, "");
}

int Client::Receive(void* buffer, int bufferSize) {
    bzero(buffer, bufferSize);
    int recverr = recv(sockfd, buffer, bufferSize, 0);
    return recverr;
}

char* Client::ReceiveNoBlock()
{
    char* recvBuffer;
    recvBuffer = new char[buffer_size];
    bzero(recvBuffer, buffer_size);
    int recverr = recv(sockfd, recvBuffer, buffer_size, MSG_DONTWAIT);
    return recvBuffer;
}

void Client::SendTo(const char* msg, string host, int port) {

    memset(&hints, 0, sizeof hints);
    hints.ai_family = IPv;
    hints.ai_socktype = sockType;


    ostringstream s;
    s << port;

    getaddrinfo(host.c_str(), s.str().c_str(), &hints, &serverInfo);



    for (p = serverInfo; p != NULL; p = p->ai_next) {

        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            continue; //bad socket, try next
        }

        sendto(sockfd, msg, strlen(msg), 0,
                serverInfo->ai_addr, serverInfo->ai_addrlen);
        break;
    }

    freeaddrinfo(serverInfo);

}

char* Client::ReceiveFromAny() {
    char *recvBuffer;
    recvBuffer = new char[buffer_size];
    bzero(recvBuffer, sizeof recvBuffer);
    struct sockaddr from;
    socklen_t length = (socklen_t)sizeof (from);
    recvfrom(sockfd, recvBuffer, buffer_size, 0, &from, &length);
    return recvBuffer;
}

void Client::BuildClient() {

}
